import { Control } from './Control';
import { Map } from '../map/Map';
import * as Util from '../core/Util';
import * as DomEvent from '../dom/DomEvent';
import * as DomUtil from '../dom/DomUtil';
import Browser from '../core/Browser';

var ukrainianFlag =
  '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="12" height="8" viewBox="0 0 12 8" class="leaflet-attribution-flag"><path fill="#4C7BE1" d="M0 0h12v4H0z"/><path fill="#FFD500" d="M0 4h12v3H0z"/><path fill="#E0BC00" d="M0 7h12v1H0z"/></svg>';

/*
 * @class Control.Attribution
 * @aka L.Control.Attribution
 * @inherits Control
 *
 * The attribution control allows you to display attribution data in a small text box on a map. It is put on the map by default unless you set its [`attributionControl` option](#map-attributioncontrol) to `false`, and it fetches attribution texts from layers with the [`getAttribution` method](#layer-getattribution) automatically. Extends Control.
 */

export var Attribution = Control.extend({
  // @section
  // @aka Control.Attribution options
  options: {
    position: 'bottomright',

    // @option prefix: String|false = 'Leaflet'
    // The HTML text shown before the attributions. Pass `false` to disable.
    prefix:
      '<a href="https://leafletjs.com" title="A JavaScript library for interactive maps">' +
      (Browser.inlineSvg ? ukrainianFlag + ' ' : '') +
      'Leaflet</a>',
  },

  initialize: function (options) {
    Util.setOptions(this, options);

    this._attributions = {};
  },

  onAdd: function (map) {
    map.attributionControl = this;
    this._container = DomUtil.create('div', 'leaflet-control-attribution');
    DomEvent.disableClickPropagation(this._container);

    // TODO ugly, refactor
    for (var i in map._layers) {
      if (map._layers[i].getAttribution) {
        this.addAttribution(map._layers[i].getAttribution());
      }
    }

    this._update();

    map.on('layeradd', this._addAttribution, this);

    return this._container;
  },

  onRemove: function (map) {
    map.off('layeradd', this._addAttribution, this);
  },

  _addAttribution: function (ev) {
    if (ev.layer.getAttribution) {
      this.addAttribution(ev.layer.getAttribution());
      ev.layer.once(
        'remove',
        function () {
          this.removeAttribution(ev.layer.getAttribution());
        },
        this,
      );
    }
  },

  // @method setPrefix(prefix: String|false): this
  // The HTML text shown before the attributions. Pass `false` to disable.
  setPrefix: function (prefix) {
    this.options.prefix = prefix;
    this._update();
    return this;
  },

  // @method addAttribution(text: String): this
  // Adds an attribution text (e.g. `'&copy; OpenStreetMap contributors'`).
  addAttribution: function (text) {
    if (!text) {
      return this;
    }

    if (!this._attributions[text]) {
      this._attributions[text] = 0;
    }
    this._attributions[text]++;

    this._update();

    return this;
  },

  // @method removeAttribution(text: String): this
  // Removes an attribution text.
  removeAttribution: function (text) {
    if (!text) {
      return this;
    }

    if (this._attributions[text]) {
      this._attributions[text]--;
      this._update();
    }

    return this;
  },

  _update: function () {
    if (!this._map) {
      return;
    }

    var attribs = [];

    for (var i in this._attributions) {
      if (this._attributions[i]) {
        attribs.push(i);
      }
    }

    var prefixAndAttribs = [];

    if (this.options.prefix) {
      prefixAndAttribs.push(this.options.prefix);
    }
    if (attribs.length) {
      prefixAndAttribs.push(attribs.join(', '));
    }

    this._container.innerHTML = prefixAndAttribs.join(
      ' <span aria-hidden="true">|</span> ',
    );
  },
});

// @namespace Map
// @section Control options
// @option attributionControl: Boolean = true
// Whether a [attribution control](#control-attribution) is added to the map by default.
Map.mergeOptions({
  attributionControl: true,
});

Map.addInitHook(function () {
  if (this.options.attributionControl) {
    new Attribution().addTo(this);
  }
});

// @namespace Control.Attribution
// @factory L.control.attribution(options: Control.Attribution options)
// Creates an attribution control.
export var attribution = function (options) {
  return new Attribution(options);
};
